﻿using Crgd.UAuthServer.Application;
using Furion.Extras.Admin.NET.Entity;
using Furion.LinqBuilder;
using System.Linq.Expressions;

namespace Furion.Extras.Admin.NET
{
    public static class QueryableExtenstions
    {
        /// <summary>
        /// 根据分页查询参数为IQueryable附加过滤条件
        /// </summary>
        /// <param name="source"></param>
        /// <param name="searchParameters"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static IQueryable<T> Search<T>(this IQueryable<T> source, PageInputBase searchParameters)
        {
            if (searchParameters.SearchParameters == null)
                return source;

            var results = source.Where(LambdaExpressionBuilder.BuildLambda<T>(searchParameters.SearchParameters));

            //无排序字段
            if (searchParameters.SortField.IsNullOrEmpty())
                return results;

            return results.ApplyOrder(searchParameters.SortField, searchParameters.SortOrder);
        }

        /// <summary>
        /// 附加排序
        /// </summary>
        /// <param name="source"></param>
        /// <param name="property"></param>
        /// <param name="sortMethod"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        private static IOrderedQueryable<T> ApplyOrder<T>(this IQueryable<T> source, string property, string sortMethod)
        {
            var type = typeof(T);
            var parameterExp = Expression.Parameter(type, "x");
            var propertyInfo = type.GetProperty(property);
            var propertyExp = Expression.Property(parameterExp, propertyInfo);
            var lambdaExp = Expression.Lambda<Func<T, dynamic>>(propertyExp, parameterExp);

            return sortMethod == "descend" ? source.OrderByDescending(lambdaExp) : source.OrderBy(lambdaExp);
        }

        /// <summary>
        /// 按租户ID过滤
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="queryable"></param>
        /// <param name="tenantId">租户ID</param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public static IQueryable<T> OnlyTenant<T>(this IQueryable<T> queryable, long tenantId) where T : DEntityTenant
        {
            return queryable.Where(p => p.TenantId == tenantId);
        }

        /// <summary>
        /// 使用当前租户ID过滤
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="queryable"></param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException"></exception>
        public static IQueryable<T> OnlyTenant<T>(this IQueryable<T> queryable) where T : DEntityTenant
        {
            if (!App.User.Identity.IsAuthenticated)
            {
                throw new InvalidOperationException("仅可在已登录的用户请求上下文中使用");
            }
            var tenantId = Convert.ToInt64(App.User.FindFirst(ClaimConst.TENANT_ID)?.Value);
            return OnlyTenant(queryable, tenantId);
        }

        /// <summary>
        /// 根据权限过滤当前用户下的数据
        /// </summary>
        /// <returns></returns>
        public static IQueryable<T> OnlyUser<T>(this IQueryable<T> queryable) where T : IDataPermissions
        {
            if (!App.User.Identity.IsAuthenticated)
            {
                throw new InvalidOperationException("仅可在已登录的用户请求上下文中使用");
            }
            var userId = Convert.ToInt64(App.User.FindFirst(ClaimConst.CLAINM_USERID).Value);
            var tenantId = Convert.ToInt64(App.User.FindFirst(ClaimConst.TENANT_ID)?.Value);

            var userService = App.GetRequiredService<IAppSysUserService>();
            var scopedIds = userService.GetUserDataScopeIdList().Result;
            return queryable.Where(p =>
                (
                    p.CreatedUserId == userId ||
                    (p.CreatedUserOrgId.HasValue && scopedIds.Contains(p.CreatedUserOrgId.Value))
                ));
        }

        /// <summary>
        /// 限定仅查询未删除的
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="queryable"></param>
        /// <returns></returns>
        public static IQueryable<T> OnlyNotDeleted<T>(this IQueryable<T> queryable) where T : DEntityTenant
        {
            return queryable.Where(p => !p.IsDeleted);
        }

        ///// <summary>
        ///// 包含已删除的数据
        ///// </summary>
        ///// <typeparam name="T"></typeparam>
        ///// <param name="queryable"></param>
        ///// <returns></returns>
        //public static IQueryable<T> IncludeDeleted<T>(this IQueryable<T> queryable) where T : DEntityBase
        //{
        //    return queryable.IgnoreQueryFilters();
        //}

        //public static IQueryable<T> IncludeAllTenant<T>(this IQueryable<T> queryable) where T : DEntityTenant
        //{
        //    return queryable.IgnoreQueryFilters().Where(p => p.IsDeleted == false);
        //}
    }
}